/*-------------------------------- Arctic Core ------------------------------
 * Copyright (C) 2013, ArcCore AB, Sweden, www.arccore.com.
 * Contact: <contact@arccore.com>
 * 
 * You may ONLY use this file:
 * 1)if you have a valid commercial ArcCore license and then in accordance with  
 * the terms contained in the written license agreement between you and ArcCore, 
 * or alternatively
 * 2)if you follow the terms found in GNU General Public License version 2 as 
 * published by the Free Software Foundation and appearing in the file 
 * LICENSE.GPL included in the packaging of this file or here 
 * <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>
 *-------------------------------- Arctic Core -----------------------------*/

#include "Std_Types.h"
#include "Mcu.h"
#include "Mcu_Arc.h"
#include "asm_ppc.h"
#include "mm.h"
#include "mpc55xx.h"
#include "io.h"
#include "isr.h"
#include "EcuM.h"

#if defined(USE_DMA)
#include "Dma.h"
#endif
#include "arc_assert.h"

#if defined(CFG_MCU_ARC_DEBUG)
#include "Ramlog.h"
#define LOG_HEX1(_str,_arg1) \
    ramlog_str(_str);ramlog_hex(_arg1);ramlog_str("\n")

#define LOG_HEX2(_str,_arg1,_str2,_arg2) \
    ramlog_str(_str);ramlog_hex(_arg1);ramlog_str(_str2);ramlog_hex(_arg2);ramlog_str("\n")

#define LOG_STR(_str) 	ramlog_str(_str)
#else
#define LOG_HEX1(_str,_arg1)
#define LOG_HEX2(_str,_arg1,_str2,_arg2)
#define LOG_STR(_str)
#endif

#if defined(CFG_VLE)
#define ADJUST_VECTOR	1
#else
#define ADJUST_VECTOR	0
#endif

struct TlbEntry TlbTable[]  = {
    // TLB Entry 0 =  1M Internal flash
    {
            0,
            (0x10000000 + (0<<16)),
            (0xC0000000 + MAS1_TSIZE_4M),
            (CFG_FLASH_START + VLE_MAS2_VAL),
            (CFG_FLASH_START + MAS3_FULL_ACCESS),
    },
    // TLB Entry 1 =  Peripheral bridge and BAM
    {
            1,
            (0x10000000 + (1<<16)),
            (0xC0000000 + MAS1_TSIZE_1M),
            (CFG_PERIPHERAL_START + VLE_MAS2_VAL +  MAS2_I),
            (CFG_PERIPHERAL_START + MAS3_FULL_ACCESS),
    },
    // TLB Entry 2 =  External RAM.
    {
            2,
            (0x10000000 + (2<<16)),
            (0xC0000000 + MAS1_TSIZE_4M),
            (CFG_EXT_FLASH_START + VLE_MAS2_VAL),
            (CFG_EXT_FLASH_START + MAS3_FULL_ACCESS),
    },
    // TLB Entry 3 =  Internal SRAM
    {
            3,
            (0x10000000+(3<<16)),
            (0xC0000000 + MAS1_TSIZE_256K),
            (CFG_SRAM_START + VLE_MAS2_VAL + MAS2_I),
            (CFG_SRAM_START + MAS3_FULL_ACCESS),
    },
    {
            UINT32_MAX
    }
};


/*
 * Configuration only support:
 * - Flash recovery only
 * - RECPTR is used to hold stack pointer when getting back from sleep
 *
 *
  */
struct Mcu_Arc_SleepPrivData sleepPrivData;



const Mcu_Arc_SleepConfigType Mcu_Arc_SleepConfig =  {
    /* Run all */
    .hlt0_run   = 0x0UL,

    /* Halt all but reserved bits */
    .hlt0_sleep = 0x3fffffffUL,

    /* Goto sleep, enable all RAM
     *     0x1-8k, 0x2-16k, 0x3-32k, 0x6-64k, 0x7-80K */
    .crp_pscr = PSCR_SLEEP | PSCR_SLP12EN | PCSR_RAMSEL(7),

    /* Point to recovery routine. If VLE is used this must be indicated */
    .z1vec = ((uint32)&Mcu_Arc_LowPowerRecoverFlash ),
    /* Not using Z0 so keep in reset */
    .z0vec = 2,
    .sleepSysClk = 0,	/* 0 - 16Mhz IRC , 1 - XOSC , 2 - PLL */
    .sleepFlags = 0,
    .pData = &sleepPrivData,
};

const struct Mcu_Arc_Config Mcu_Arc_ConfigData = {
        .sleepConfig = &Mcu_Arc_SleepConfig,
        .tblTable = TlbTable,
};


/**
 * @param sleepCfg
 */ 
void Mcu_Arc_SetModePre2( Mcu_ModeType mcuMode, const struct Mcu_Arc_SleepConfig *sleepCfg ) {
    uint32_t timeout = 0;

    if( mcuMode == McuConf_McuModeSettingConf_NORMAL ) {
        mcuMode = McuConf_McuModeSettingConf_RUN;
    }

    if( McuConf_McuModeSettingConf_RUN == mcuMode ) {
        SIU.HLT.R = sleepCfg->hlt0_run;
    } else if( McuConf_McuModeSettingConf_SLEEP == mcuMode  ) {

#if defined(USE_DMA)
        Dma_DeInit();
#endif

        LOG_HEX1("CRP Sleep clock select: ", sleepCfg->sleepSysClk);

        /* Set system clock to 16Mhz IRC */
        SIU.SYSCLK.B.SYSCLKSEL = sleepCfg->sleepSysClk;

        if( sleepCfg->sleepFlags & SLEEP_FLG_POWERDOWN_FLASH ) {
            /* Set MCR[STOP]  (should work if FASTREC if OFF */
            SET32( 0xffff8000UL + 0, (1<<(31-25)) );
        }

        Irq_Disable();

        /* Clear FLAGS first */
        LOG_STR("CRP: Clearing wakeup flags\n");
        SET32(CRP_PSCR, 0xc7ff0000UL );
        SET32(CRP_RTCSC, (1<<(31-2)) );	/* Clear RTCF */

        /* Write Sleep config */
        WRITE32(CRP_PSCR, sleepCfg->crp_pscr);

        LOG_HEX1("CRP: Z1VEC: ", sleepCfg->z1vec );
        WRITE32(CRP_Z1VEC, sleepCfg->z1vec | ADJUST_VECTOR);
        LOG_HEX1("CRP: Z0VEC: ", sleepCfg->z0vec );
        WRITE32(CRP_Z0VEC, sleepCfg->z0vec | ADJUST_VECTOR);

        ASSERT( sleepCfg->pData != NULL );

        LOG_HEX1("HLT: ", sleepCfg->hlt0_sleep );
        sleepCfg->pData->hlt0 = SIU.HLT.R;
        sleepCfg->pData->swt_cr = MCM.SWTCR.R;
        SIU.HLT.R = sleepCfg->hlt0_sleep;

        while((SIU.HLTACK.R != sleepCfg->hlt0_sleep) && (timeout++<HLT_TIMEOUT)) {}

        Mcu_Arc_EnterLowPower(mcuMode);
        /* back from sleep */

        /* Setup exceptions and INTC again */
        Os_IsrInit();

        /* Restore watchdog */
        MCM.SWTCR.R = sleepCfg->pData->swt_cr;

#if defined(USE_ECUM_FIXED) || defined(USE_ECUM_FLEXIBLE)
        EcuM_CheckWakeup( 0x3fffffffUL );
#endif
        /* Clear sleep flags to allow pads to operate */
        CRP.PSCR.B.SLEEPF = 0x1;
    }
}


/**
 * @param sleepCfg
 */
void Mcu_Arc_SetModePost2( Mcu_ModeType mcuMode, const struct Mcu_Arc_SleepConfig *sleepCfg ) {

    if( mcuMode == McuConf_McuModeSettingConf_NORMAL ) {
        mcuMode = McuConf_McuModeSettingConf_RUN;
    }

    if( McuConf_McuModeSettingConf_RUN == mcuMode ) {

    } else if( McuConf_McuModeSettingConf_SLEEP == mcuMode  ) {
    }
}



